---
id: getting-started
title: Quick Introduction
sidebar_label: Quick Introduction
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import InstallationInstructions from '../components/_installation_instructions.mdx'
import Discord from '../../website/src/assets/icons/discord-white.svg'

Atlas is an open-source tool designed to help software engineers, DBAs and DevOps
practitioners to manage their database schemas. Atlas users can use the [Atlas DDL](../atlas-schema/sql-resources)
(data-definition language) or SQL to describe the desired database schema and use the command-line
tool to plan and apply the migrations to their systems.

### Installation

<InstallationInstructions />

The binaries distributed in official releases are released under the
[Apache 2 License](https://github.com/ariga/atlas/blob/master/LICENSE). If you would like to build Atlas from source
follow the instructions [here](https://atlasgo.io/cli-reference#building-from-source).

### Start a local database container

For the purpose of this guide, we will start a local Docker container running MySQL.
```shell
docker run --rm -d --name atlas-demo -p 3306:3306 -e MYSQL_ROOT_PASSWORD=pass -e MYSQL_DATABASE=example mysql
```

For this example, we will start with a schema that represents a `users` table, in which each user has an ID and a name:
```sql
CREATE table users (
  id int PRIMARY KEY,
  name varchar(100)
);
```

To create the table above on our local database, we can run the following command:
```shell
docker exec atlas-demo mysql -ppass -e 'CREATE table example.users(id int PRIMARY KEY, name varchar(100))'
```

### Inspecting our database

The `atlas schema inspect` command supports reading the database description provided by a URL and outputting it in
three different formats: [Atlas DDL](../atlas-schema/sql.mdx) (default), SQL, and JSON. In this guide, we will
demonstrate the flow using both the Atlas DDL and SQL formats, as the JSON format is often used for processing the
output using `jq`.

<Tabs>
<TabItem value="hcl" label="Atlas DDL (HCL)" default>

To inspect our locally-running MySQL instance, use the `-u` flag and write the output to a file named `schema.hcl`:

```shell
atlas schema inspect -u "mysql://root:pass@localhost:3306/example" > schema.hcl
```

Open the `schema.hcl` file to view the Atlas schema that describes our database.

```hcl title="schema.hcl"
table "users" {
  schema = schema.example
  column "id" {
    null = false
    type = int
  }
  column "name" {
    null = true
    type = varchar(100)
  }
  primary_key {
    columns = [column.id]
  }
}
```
This block represents a [table](../atlas-schema/sql.mdx#table) resource with `id`, and `name`
columns. The `schema` field references the `example` schema that is defined elsewhere
in this document. In addition, the `primary_key` sub-block defines the `id` column as
the primary key for the table. Atlas strives to mimic the syntax of the database that the user is working against. In this case, the
type for the `id` column is `int`, and `varchar(100)` for the `name` column.

</TabItem>
<TabItem value="sql" label="SQL">

To inspect our locally-running MySQL instance, use the `-u` flag and write the output to a file named `schema.sql`:

```shell
atlas schema inspect -u "mysql://root:pass@localhost:3306/example" --format '{{ sql . }}' > schema.sql
```

Open the `schema.sql` file to view the inspected SQL schema that describes our database.

```sql title="schema.sql"
-- create "users" table
CREATE TABLE `users` (`id` int NOT NULL, `name` varchar(100) NULL, PRIMARY KEY (`id`)) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
```

</TabItem>
</Tabs>

Now, consider we want to add a `blog_posts` table and have our schema represent a simplified
blogging system.


<p style={{textAlign: "center"}}><a href="https://gh.atlasgo.cloud/explore/9717d499"><img src="https://atlasgo.io/uploads/images/blog-erd.png" alt="Blog ERD"/></a></p>

Let's add the following to our inspected schema, and use Atlas to plan and apply the changes to our database.

<Tabs>
<TabItem value="hcl" label="Atlas DDL (HCL)" default>

Edit the `schema.hcl` file and add the following `table` block:

```hcl title="schema.hcl" {22-25}
table "blog_posts" {
  schema = schema.example
  column "id" {
    null = false
    type = int
  }
  column "title" {
    null = true
    type = varchar(100)
  }
  column "body" {
    null = true
    type = text
  }
  column "author_id" {
    null = true
    type = int
  }
  primary_key {
    columns = [column.id]
  }
  foreign_key "author_fk" {
    columns     = [column.author_id]
    ref_columns = [table.users.column.id]
  }
}
```
In addition to the elements we saw in the `users` table, here we can find a [foreign key](../atlas-schema/sql.mdx#foreign-key)
block, declaring that the `author_id` column references the `id` column on the
`users` table.
</TabItem>
<TabItem value="sql" label="SQL">

Edit the `schema.sql` file and add the following `CREATE TABLE` statement:

```sql title="schema.sql"
-- create "blog_posts" table
CREATE TABLE `blog_posts` (
  `id` int NOT NULL,
  `title` varchar(100) NULL,
  `body` text NULL,
  `author_id` int NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `author_fk` FOREIGN KEY (`author_id`) REFERENCES `example`.`users` (`id`)
);
```
</TabItem>
</Tabs>

Now, let's apply these changes by running a migration.
In Atlas, migrations can be applied in two types of workflows: _declarative_ and _versioned_.

### Declarative Migrations
The declarative approach requires the user to define the _desired_ end schema, and Atlas provides
a safe way to alter the database to get there. Let's see this in action.

Continuing the example, in order to apply the changes to our database we will run the `apply` command:

<Tabs>
<TabItem value="hcl" label="Atlas DDL (HCL)" default>

```shell
atlas schema apply \
  -u "mysql://root:pass@localhost:3306/example" \
  --to file://schema.hcl
```

</TabItem>
<TabItem value="sql" label="SQL">

```shell
atlas schema apply \
  -u "mysql://root:pass@localhost:3306/example" \
  --to file://schema.sql \
  --dev-url "docker://mysql/8/example"
```

</TabItem>
</Tabs>

Atlas presents the plan it created by displaying the SQL statements. For example, for a MySQL database we will see
the following:

```console
-- Planned Changes:
-- Create "blog_posts" table
// highlight-next-line-info
CREATE TABLE `example`.`blog_posts` (`id` int NOT NULL, `title` varchar(100) NULL, `body` text NULL, `author_id` int NULL, PRIMARY KEY (`id`), INDEX `author_id` (`author_id`), CONSTRAINT `author_fk` FOREIGN KEY (`author_id`) REFERENCES `example`.`users` (`id`))
Use the arrow keys to navigate: ↓ ↑ → ←
? Are you sure?:
  ▸ Apply
    Abort
```
Apply the changes, and that's it! You have successfully run a declarative migration.

You can reinspect the database by running the `inspect` command again to ensure that the changes have been made to the
schema:

<Tabs>
<TabItem value="hcl" label="Atlas DDL (HCL)" default>

```shell
atlas schema inspect -u "mysql://root:pass@localhost:3306/example"
```
</TabItem>
<TabItem value="sql" label="SQL">

```shell
atlas schema inspect -u "mysql://root:pass@localhost:3306/example" --format '{{ sql . }}'
```
</TabItem>
</Tabs>

### Versioned Migrations
Alternatively, the versioned migration workflow, sometimes called "change-based migrations", allows each change to the
database schema to be checked into source control and reviewed during code-review. Users can still benefit from Atlas
intelligently planning migrations for them, however they are not automatically applied.

To start, we will calculate the difference between the _desired_ and _current_ state of the database by running the `atlas
migrate diff` command.

To run this command, we need to provide the necessary parameters:

* `--dir` the URL to the migration directory, by default it is `file://migrations`.
* `--to` the URL of the desired state. A state can be specified using a database URL, HCL or SQL schema, or another migration directory.
* `--dev-url` a URL to a [Dev Database](/concepts/dev-database) that will be used to compute the diff.

<Tabs>
<TabItem value="hcl" label="Atlas DDL (HCL)" default>

```shell
atlas migrate diff create_blog_posts \
  --dir "file://migrations" \
  --to "file://schema.hcl" \
  --dev-url "docker://mysql/8/example"
```
</TabItem>
<TabItem value="sql" label="SQL">

```shell
atlas migrate diff create_blog_posts \
  --dir "file://migrations" \
  --to "file://schema.sql" \
  --dev-url "docker://mysql/8/example"
```
</TabItem>
</Tabs>

Run `ls migrations`, and you will notice that Atlas has created two files:

<Tabs
defaultValue="migration_file"
values={[
{label: '20220811074144_create_blog_posts.sql', value: 'migration_file'},
{label: 'atlas.sum', value: 'sum_file'},
]}>
<TabItem value="migration_file">

```sql
-- create "blog_posts" table
CREATE TABLE `example`.`blog_posts` (`id` int NOT NULL, `title` varchar(100) NULL, `body` text NULL, `author_id` int NULL, PRIMARY KEY (`id`), INDEX `author_id` (`author_id`), CONSTRAINT `author_fk` FOREIGN KEY (`author_id`) REFERENCES `example`.`users` (`id`))
```

</TabItem>
<TabItem value="sum_file">

In addition to the migration directory, Atlas maintains a file name `atlas.sum` which is used
to ensure the integrity of the migration directory and force developers to deal with situations
where migration order or contents was modified after the fact.

```text
h1:t1fEP1rSsGf1gYrYCjsGyEyuM0cnhATlq93B7h8uXxY=
20220811074144_create_blog_posts.sql h1:liZcCBbAn/HyBTqBAEVar9fJNKPTb2Eq+rEKZeCFC9M=
```

</TabItem>
</Tabs>

Now that we have our migration files ready, you can use your favorite migration tool to apply the changes generated by
Atlas.

### Next Steps
In this short tutorial we learned how to use Atlas to inspect databases, as well as use declarative and versioned
migrations. Read more about the use-cases for the two approaches [here](/concepts/declarative-vs-versioned) to help you
decide which workflow works best for you.

:::info Need help getting started?

We have a super friendly [#getting-started](https://discord.gg/8mvDUG22) channel on our community
chat on Discord.


For web-based, free, and fun (GIFs included) support:

<a href={"https://discord.gg/zZ6sWVg6NT"} className={"join-discord"}>
    <Discord />
    <span>
        Join our Discord server
    </span>
</a>

:::
